package com.ticket.web.controller.yanchu;

import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.service.WxPayService;
import com.ticket.common.annotation.Log;
import com.ticket.common.constant.CacheConstants;
import com.ticket.common.constant.HttpStatus;
import com.ticket.common.constant.PerformConstants;
import com.ticket.common.core.controller.BaseController;
import com.ticket.common.core.domain.AjaxResult;
import com.ticket.common.core.domain.model.LoginUser;
import com.ticket.common.core.page.TableDataInfo;
import com.ticket.common.core.redis.RedisCache;
import com.ticket.common.enums.BusinessType;
import com.ticket.common.exception.ServiceException;
import com.ticket.common.utils.DateUtils;
import com.ticket.common.utils.SecurityUtils;
import com.ticket.common.utils.poi.ExcelUtil;
import com.ticket.system.domain.YanchuOrder;
import com.ticket.system.domain.YanchuSeat;
import com.ticket.system.domain.YanchuSession;
import com.ticket.system.domain.vo.*;
import com.ticket.system.service.IYanchuOrderService;
import com.ticket.system.service.IYanchuSeatService;
import com.ticket.system.service.IYanchuSessionService;
import io.swagger.annotations.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * 订单Controller
 * 
 */
@Api(description = "订单管理")
@RestController
@RequestMapping("/system/order")
public class YanchuOrderController extends BaseController
{
    private static final Logger logger = LoggerFactory.getLogger(YanchuOrderController.class);
    @Resource
    private IYanchuOrderService yanchuOrderService;
    @Resource
    private IYanchuSeatService yanchuSeatService;
    @Resource
    private IYanchuSessionService yanchuSessionService;
    @Resource
    private WxPayService wxPayService;

    @Resource
    private RedisCache redisCache;

    /**
     * 管理端查询订单列表
     */
    @ApiOperation("管理端查询订单列表")
    @ApiImplicitParam(name = "query", value = "订单对象", dataType = "QueryOrderListVO", dataTypeClass = QueryOrderListVO.class)
    @PreAuthorize("@ss.hasPermi('system:order:list')")
    @GetMapping("/list")
    public TableDataInfo list(QueryOrderListVO query)
    {
        startPage();
        List<YanchuOrderVO> list = yanchuOrderService.selectOrderList(query);
        return getDataTable(list);
    }

    @ApiOperation("小程序端我的订单列表")
    @ApiImplicitParam(name = "yanchuOrder", value = "订单对象", dataType = "YanchuOrder", dataTypeClass = YanchuOrder.class)
    @GetMapping("/listOrder")
    public TableDataInfo listOrder(YanchuOrder yanchuOrder)
    {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        yanchuOrder.setUserId(loginUser.getUser().getUserId());
        startPage();
        List<OrderVo> list = yanchuOrderService.selectUserOrderVoList(yanchuOrder);
        return getDataTable(list);
    }

    /**
     * 导出订单列表
     */
    @PreAuthorize("@ss.hasPermi('system:order:export')")
    @Log(title = "订单", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, YanchuOrder yanchuOrder)
    {
        List<YanchuOrder> list = yanchuOrderService.selectYanchuOrderList(yanchuOrder);
        ExcelUtil<YanchuOrder> util = new ExcelUtil<>(YanchuOrder.class);
        util.exportExcel(response, list, "订单数据");
    }

    /**
     * 获取订单详细信息
     */
    @ApiOperation("获取订单详细信息")
    @ApiImplicitParam(name = "id", value = "订单编码", dataType = "Long", dataTypeClass = Long.class)
    @PreAuthorize("@ss.hasPermi('system:order:query')")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "订单详情",response = OrderVo.class)
    })
    @GetMapping(value = "/{id}",produces = {"application/json"})
    public AjaxResult getInfo(@PathVariable("id") Long id)
    {
        return success(yanchuOrderService.selectYanchuOrderById(id));
    }

    /**
     * PC获取订单详情基本信息
     * @param orderId
     * @return
     */
    @GetMapping("/getDetailInfo")
    public AjaxResult getDetailInfo(String orderId)
    {
        return success(yanchuOrderService.getDetailInfo(orderId));
    }

    /**
     * PC获取订单详情购票明细
     * @param orderId
     * @return
     */
    @GetMapping("/getTicketDetail")
    public AjaxResult getTicketDetail(String orderId)
    {
        return success(yanchuOrderService.getTicketDetail(orderId));
    }

    /**
     * 小程序订单详细信息
     */
    @ApiOperation("小程序订单详情")
    @ApiImplicitParam(name = "id", value = "订单编码", dataType = "Long", dataTypeClass = Long.class)
    @GetMapping(value = "/getOrderInfo")
    public AjaxResult getOrderInfo(Long id)
    {
        return success(yanchuOrderService.selectOrderVoById(id));
    }

    /**
     * 小程序订单支付补偿
     */
    @ApiOperation("小程序订单支付补偿查询")
    @ApiImplicitParam(name = "orderNo", value = "订单编码", dataType = "String", dataTypeClass = String.class)
    @GetMapping(value = "/getOrderInfo/forAllUser")
    public AjaxResult orderPayInfo(@RequestParam(name = "orderNo")String orderNo)
    {
        try {
            return success(yanchuOrderService.selectOrderPayByOrderNo(orderNo));
        }catch (Exception e){
            logger.error("orderPayInfo error",e);
            return error("补偿查询失败");
        }
    }

    /**
     * 微信订单查询
     */
    @ApiOperation("微信订单查询")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "订单编码", dataType = "Long", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "sessionId", value = "场次编码", dataType = "Long", dataTypeClass = Long.class)
    })
    @GetMapping(value = "/getPayInfo")
    public AjaxResult getPayInfo(@RequestParam(name = "id")Long id,@RequestParam(name = "sessionId")Long sessionId)
    {
        try {
            YanchuSession session = yanchuSessionService.selectYanchuSessionById(sessionId);
            if(null == session || (!session.getStatus().equals(PerformConstants.SESSION_UP) && !session.getStatus().equals(PerformConstants.SESSION_SELLING))){
                return error("场次信息不正确！");
            }

            WxPayMpOrderResult result = redisCache.getCacheObject(CacheConstants.ORDER_UNI_KEY+id);
            return AjaxResult.success(result);
        }catch (Exception e){
            logger.error("orderPayInfo error",e);
            return error("查询失败");
        }
    }

    /**
     * 新增订单
     */
    @ApiOperation("下单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderParamVo", value = "下单请求对象", dataType = "OrderParamVo", dataTypeClass = OrderParamVo.class)
    })
    @Log(title = "订单下单", businessType = BusinessType.INSERT)
    @PostMapping("/unifiedOrder")
    public AjaxResult unifiedOrder(@RequestBody @Valid OrderParamVo orderParamVo){
        try {
            BigDecimal total = orderParamVo.getTotalMoney();
            BigDecimal payTotal = orderParamVo.getBalanceAmt().add(orderParamVo.getCardAmt()).add(orderParamVo.getWechatAmt());
            if(null != total && total.compareTo(payTotal)!=0){
                return AjaxResult.error("下单金额不正确");
            }
            if(CollectionUtils.isNotEmpty(orderParamVo.getCardVos())){
                BigDecimal cardTotal = orderParamVo.getCardVos().stream().map(CardVo::getAmount).reduce(BigDecimal.ZERO,BigDecimal::add);
                if(cardTotal.compareTo(orderParamVo.getCardAmt()) != 0){
                    return AjaxResult.error("观演卡金额不正确");
                }
            }
            //根据场次编号查询场次信息
            YanchuSession yanchuSession = yanchuSessionService.selectYanchuSessionById(orderParamVo.getSessionId());
            if (null == yanchuSession) {
                throw new ServiceException("未查询到演出场次，下单失败！");
            }
            if (!yanchuSession.getStatus().equals(PerformConstants.SESSION_UP) && !yanchuSession.getStatus().equals(PerformConstants.SESSION_SELLING)) {
                throw new ServiceException("演出场次状态不正确，下单失败！");
            }
//            if(PerformConstants.LIMIT.equals(yanchuSession.getIsLimit()) && yanchuSession.getLimitCount()<orderParamVo.getSeatVos().size()){
//                throw new ServiceException("每笔订单限购"+yanchuSession.getLimitCount()+"张！");
//            }
            AjaxResult result = null;
            if(orderParamVo.getWechatAmt().compareTo(BigDecimal.ZERO) == 0){
                result = yanchuOrderService.insertNoPayYanchuOrder(orderParamVo,yanchuSession);
            }else{
                result = yanchuOrderService.insertYanchuOrder(orderParamVo,yanchuSession);
            }
            if((Integer)result.get(AjaxResult.CODE_TAG) != HttpStatus.SUCCESS){
                return result;
            }
            //批量修改缓存状态
            List<YanchuSeat> seatList = (List<YanchuSeat>)result.get("seatList");
            yanchuSeatService.refreshTicketList(seatList,orderParamVo.getSessionId());
            return result;
        }catch (ServiceException se){
            logger.error("下单失败！", se);
            return AjaxResult.error(se.getMessage());
        } catch (Exception e) {
            logger.error("下单失败！", e);
            return AjaxResult.error("下单失败，请稍后重试！");
        }
    }

    /**
     * 支付回调
     */
    @PostMapping("/payNotify/forAllUser")
    public String payNotify(HttpServletRequest request){
        try {
            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult);

            // 加入自己处理订单的业务逻辑，需要判断订单是否已经支付过，否则可能会重复调用
            String outTradeNo = result.getOutTradeNo();
            String transactionId = result.getTransactionId();
            String totalFee = BaseWxPayResult.fenToYuan(result.getTotalFee());
            yanchuOrderService.notifyOrder(outTradeNo, new BigDecimal(totalFee),transactionId,null);
            return WxPayNotifyResponse.success("处理成功!");
        } catch (Exception e) {
            logger.error("微信回调结果异常", e);
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }

    /**
     * 新增后台出票
     */
    @ApiOperation("新增后台出票")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderParamVo", value = "出票请求对象", dataType = "OrderParamVo", dataTypeClass = OrderParamVo.class)
    })
    @PreAuthorize("@ss.hasPermi('backend:order:out')")
    @Log(title = "新增后台出票", businessType = BusinessType.INSERT)
    @PostMapping("/unifiedTicket")
    public AjaxResult unifiedTicket(@RequestBody @Valid OrderParamVo orderParamVo){
        try {
            BigDecimal total = orderParamVo.getTotalMoney();
            BigDecimal payTotal = orderParamVo.getYingfuMoney().subtract(orderParamVo.getDiscountAmt());
            if(null != total && total.compareTo(payTotal)!=0){
                return AjaxResult.error("出票金额不正确");
            }
            if(CollectionUtils.isNotEmpty(orderParamVo.getSeatVos())){
                BigDecimal yingfuTotal = orderParamVo.getSeatVos().stream().map(SeatVo::getYingfuMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
                BigDecimal jianmianTotal = orderParamVo.getSeatVos().stream().map(SeatVo::getJianmianMoney).reduce(BigDecimal.ZERO,BigDecimal::add);
                if(yingfuTotal.subtract(jianmianTotal).compareTo(orderParamVo.getTotalMoney()) != 0){
                    return AjaxResult.error("出票金额不正确");
                }
            }
            //根据场次编号查询场次信息
            YanchuSession yanchuSession = yanchuSessionService.selectYanchuSessionById(orderParamVo.getSessionId());
            if (null == yanchuSession) {
                throw new ServiceException("未查询到演出场次，下单失败！");
            }
            if(yanchuSession.getStatus().equals(PerformConstants.SESSION_DOWN)){
                throw new ServiceException("场次已停售，不可出票！");
            }
            if(yanchuSession.getStatus().equals(PerformConstants.SESSION_CANCEL)){
                throw new ServiceException("场次已取消，不可出票！");
            }
            if(DateUtils.differentByMillisecond(new Date(),yanchuSession.getEndTime()) > 0){
                throw new ServiceException("演出已结束，不可出票！");
            }
            AjaxResult result = yanchuOrderService.insertYanchuBackendOrder(orderParamVo,yanchuSession);
            if((Integer)result.get(AjaxResult.CODE_TAG) != HttpStatus.SUCCESS){
                return result;
            }
            //批量修改缓存状态
            List<YanchuSeat> seatList = (List<YanchuSeat>)result.get("seatList");
            yanchuSeatService.refreshTicketList(seatList,orderParamVo.getSessionId());
            return result;
        }catch (ServiceException se){
            logger.error("下单失败！", se);
            return AjaxResult.error(se.getMessage());
        } catch (Exception e) {
            logger.error("下单失败！", e);
            return AjaxResult.error("下单失败，请稍后重试！");
        }
    }

    /**
     * 付款后台出票
     */
    @ApiOperation("付款后台出票")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderParamVo", value = "付款后台出票请求对象", dataType = "OrderParamVo", dataTypeClass = OrderParamVo.class)
    })
    @PreAuthorize("@ss.hasPermi('backend:order:pay')")
    @Log(title = "付款后台出票", businessType = BusinessType.INSERT)
    @PostMapping("/payTicket")
    public AjaxResult payTicket(@RequestBody @Valid OrderPayParamVo orderPayParamVo){
        try {
            return success(yanchuOrderService.payYanchuOrder(orderPayParamVo));
        }catch (ServiceException se){
            logger.error("下单失败！", se);
            return AjaxResult.error(se.getMessage());
        } catch (Exception e) {
            logger.error("下单失败！", e);
            return AjaxResult.error("付款后台出票失败，请稍后重试！");
        }
    }

    /**
     * 修改订单
     */
    @PreAuthorize("@ss.hasPermi('system:order:edit')")
    @Log(title = "订单", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody YanchuOrder yanchuOrder)
    {
        return toAjax(yanchuOrderService.updateYanchuOrder(yanchuOrder));
    }

    /**
     * 小程序删除订单
     */
    @ApiOperation("小程序删除订单")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "id", dataType = "Long", dataTypeClass = Long.class)
    })
	@DeleteMapping("/removeOrder")
    public AjaxResult removeOrder(@RequestParam Long id)
    {
        return toAjax(yanchuOrderService.deleteYanchuOrderById(id));
    }

    /**
     * 删除订单
     */
    @Log(title = "订单", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids)
    {
        return toAjax(yanchuOrderService.deleteYanchuOrderByIds(ids));
    }
    /**
     * 订单取消
     */
    @ApiOperation("订单取消")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "id", dataType = "Long", dataTypeClass = Long.class)
    })
    @PostMapping("/cancel")
    public AjaxResult cancel(@RequestParam Long id)
    {
        return toAjax(yanchuOrderService.cancelOrder(id));
    }
    /**
     * 查询常用观演人信息关联关系列表
     */
    @PreAuthorize("@ss.hasPermi('system:moviegoer:list')")
    @ApiImplicitParams({
            @ApiImplicitParam(name="deptId",value = "剧院编号",dataType = "int",dataTypeClass = Integer.class),
            @ApiImplicitParam(name="performId",value = "演出编号",dataType = "int",dataTypeClass = Integer.class),
            @ApiImplicitParam(name="sessionId",value = "场次编号",dataType = "int",dataTypeClass = Integer.class),
            @ApiImplicitParam(name="orderStatus",value = "订单状态 1：已占票等待支付，2：已支付，3：超时未支付自动取消  4已验票 5已支付等待退款 6已退款",dataType = "int",dataTypeClass = Integer.class),
            @ApiImplicitParam(name="orderId",value = "订单编号",dataType = "String",dataTypeClass = String.class),
            @ApiImplicitParam(name="ticketBuyer",value = "购票人姓名",dataType = "String",dataTypeClass = String.class),
            @ApiImplicitParam(name="phone",value = "购票人手机号",dataType = "String",dataTypeClass = String.class)
    })
    @GetMapping("/pageList")
    public TableDataInfo pageList(Long deptId,Long performId,Long sessionId,Integer orderStatus,
                                  String orderId,String ticketBuyer,String phone,HttpServletRequest request) {
        startPage();
        List<OrderVo> list = yanchuOrderService.selectYanchuOrderPageList(deptId,performId,sessionId,
                orderStatus, orderId, ticketBuyer, phone);
        return getDataTable(list);
    }

    @ApiOperation("场次是否全部退款")
    @ApiImplicitParam(name = "sessionId",value = "场次id",required = true,dataType = "long",dataTypeClass = Long.class)
    @GetMapping("/checkOrderStatus")
    public AjaxResult checkOrderStatus(@RequestParam Long sessionId){
        return AjaxResult.success(yanchuOrderService.checkOrderStatus(sessionId));
    }


    @ApiOperation("管理端导出订单列表")
    @PreAuthorize("@ss.hasPermi('system:detail:export')")
    @Log(title = "导出订单列表", businessType = BusinessType.EXPORT)
    @PostMapping("/exportOrderList")
    public void exportOrderList(HttpServletResponse response, QueryOrderListVO query) {
        yanchuOrderService.exportOrderList(response, query);
    }

    @ApiOperation("管理端根据条件得出订单导出条数")
    @PreAuthorize("@ss.hasPermi('system:detail:export')")
    @PostMapping("/getExportCount")
    public AjaxResult getExportCount(QueryOrderListVO query) {
        return AjaxResult.success(yanchuOrderService.getExportCount(query));
    }


}
